﻿using UnityEngine;
using System.Collections;

/// <summary>
/// Class used both for updating the timer and managing the different game states.
/// </summary>
public class TimeForWin : MonoBehaviour {
	
	/// <summary>
	/// Possible game modes for the prototype.
	/// </summary>
	public enum GameState { PreLaunch, Active, Success }
	
	/// <summary>
	/// GUIText instance used for rendering the elapsed time since ball launch.
	/// </summary>
	public GUIText ElapsedTimeDisplay;
	
	/// <summary>
	/// GUIText instance used for rendering the best time yet reached.
	/// </summary>
	public GUIText BestTimeDisplay;
	
	/// <summary>
	/// Script instance responsible for the ball's motion.
	/// </summary>
	public BallBounce Ball;
	
	/// <summary>
	/// Script instance responsible for launching the ball and beginning the game.
	/// </summary>
	public Launcher LauncherInstance;
	
	/// <summary>
	/// The dimensions of the dialog displayed after a successful attempt to land the ball.
	/// </summary>
	public Vector2 DialogDimensions;
	
	/// <summary>
	/// The region of the dialog used to render the "Retry" button.
	/// This region is calculated using the upper-left corner of the dialog as the origin.
	/// </summary>
	public Rect DialogButtonRegion;
	
	/// <summary>
	/// The displacement the edges of the "Reset" button should have from the lower-right corner of the screen.
	/// </summary>
	public Vector2 ResetButtonOffset;
	
	/// <summary>
	/// Storage variable for the ElapsedTime property.
	/// </summary>
	float elapsedTime = 0F;
	/// <summary>
	/// Gets or sets the elapsed time. Automatically updates the matching GUIText instance.
	/// </summary>
	/// <value>
	/// The elapsed time.
	/// </value>
	float ElapsedTime
	{
		get { return elapsedTime; }
		set
		{
			elapsedTime = value;
			ElapsedTimeDisplay.text = elapsedTime.ToString("0.##");
		}
	}
	
	/// <summary>
	/// Storage variable for the BestTime property.
	/// </summary>
	float bestTime = Mathf.Infinity;
	/// <summary>
	/// Gets or sets the best time. Automatically updates the matching GUIText instance.
	/// </summary>
	/// <value>
	/// The best time.
	/// </value>
	float BestTime
	{
		get { return bestTime; }
		set
		{
			bestTime = value;
			BestTimeDisplay.text = bestTime.ToString("0.##");
		}
	}
	
	/// <summary>
	/// The current mode of the game.
	/// </summary>
	GameState CurrentMode;

	// Use this for initialization
	void Start () {
		Ball.OnGoalReached += OnGoalReached;
		LauncherInstance.OnBallLaunch += OnBallLaunched;
		CurrentMode = GameState.PreLaunch;
	}
	
	/// <summary>
	/// When the ball contacts any box marked as a goal box, this method will be called.
	/// </summary>
	void OnGoalReached()
	{
		CurrentMode = GameState.Success;
		
		Ball.Stop();
		
		if (ElapsedTime < BestTime)
		{
			BestTime = ElapsedTime;
		}
	}
	
	void OnGUI()
	{
		switch (CurrentMode)
		{
		case GameState.PreLaunch:
			break;
		case GameState.Active:
			float rightSpace = Screen.width - (DialogDimensions.x + ResetButtonOffset.x);
			float topSpace = Screen.height - (DialogDimensions.y + ResetButtonOffset.y);
			GUILayout.BeginVertical();
			GUILayout.Space(topSpace);
			GUILayout.BeginHorizontal();
			GUILayout.Space(rightSpace);
			if (GUILayout.Button("Reset"))
				Reset();
			GUILayout.Space(ResetButtonOffset.x);
			GUILayout.EndHorizontal();
			GUILayout.Space(ResetButtonOffset.y);
			GUILayout.EndVertical();
			break;
		case GameState.Success:
			Vector2 center = new Vector2((float)Screen.width * 0.5F, (float)Screen.height * 0.5F);
			Vector2 dialogOffset = center - DialogDimensions * 0.5F;
			Rect dialogRegion = new Rect(dialogOffset.x, dialogOffset.y, DialogDimensions.x, DialogDimensions.y);
			GUI.Box(dialogRegion, string.Empty);
			GUI.BeginGroup(dialogRegion);
			if (GUI.Button(DialogButtonRegion, "Try Again"))
				Reset();
			GUI.EndGroup();
			break;
		}
	}
	
	/// <summary>
	/// Resets the ball and elapsed time, so that the ball be launched again for a new try.
	/// </summary>
	void Reset()
	{
		ElapsedTime = 0F;
		Ball.Reset();
		LauncherInstance.gameObject.SetActive(true);
		CurrentMode = GameState.PreLaunch;
	}
	
	/// <summary>
	/// This is assigned to a callback in the BallBounce class; its function is to begin the timer and await the win condition.
	/// </summary>
	void OnBallLaunched()
	{
		CurrentMode = GameState.Active;
	}
	
	// Update is called once per frame
	void Update () {
		// Perform timer updates only if the ball is actually actively moving
		if (CurrentMode != GameState.Active)
			return;
		
		// Advance the elapsed time counter and update the appropriate text label
		ElapsedTime += Time.deltaTime;
	}
}
